package com.isomentricengine.character
{
	import com.isomentricengine.core.CoordinateUtil;
	import com.isomentricengine.core.GameEngine;
	import com.isomentricengine.map.IMap;
	import com.isomentricengine.tile.BaseTile;
	import com.isomentricengine.vo.Coordinates;
	import com.isomentricengine.vo.CornersData;
	import com.medusa.core.extension.SpriteExtension;
	
	import flash.display.Graphics;
	import flash.display.Sprite;

	public class BaseCharacter extends SpriteExtension
	{
		private var base:Sprite;
		private var originalSpeed:Number;
		private var originalSpeedSet:Boolean;

		protected var _charWidth:Number;
		protected var _charHeight:Number;
		protected var _defColor:Number;
		protected var _currentCoordinates:Coordinates;
		protected var _cornerTiles:CornersData;
		protected var _speed:Number;
		protected var _jumpSpeed:Number;
		protected var _jumpStart:Number;
		protected var _gravity:Number;
		protected var _controllable:Boolean;
		protected var _isJumping:Boolean;
		protected var _isClimbing:Boolean;
		protected var _engine:GameEngine;
		protected var _map:IMap;
		
		public function BaseCharacter(w:Number, h:Number)
		{
			originalSpeedSet = false;
			base = null;
			charWidth = w;
			charHeight = h;
			defColor = 0xFF0000;
			controllable = false;
			isJumping = false;
			isClimbing = false;
			build();
		}
		
		private function build():void
		{
			if(base != null){
				removeAllChildren();
				base = null;
			}
			
			base = new Sprite();
			
			var g:Graphics = base.graphics;
			g.beginFill(defColor);
			g.drawRect(0, 0, charWidth, charHeight);
			g.endFill();
			
			base.x = (charWidth * 0.5) * -1;
			base.y = (charHeight * 0.5) * -1;
			
			addChild(base)
		}
		
		public function move(xFactor:Number, yFactor:Number, jumpFactor:Number = 0):void
		{
			var newSpeed:Number;
			if(Math.abs(jumpFactor) == 1){
				newSpeed = jumpSpeed * jumpFactor;
			}else{
				newSpeed = originalSpeed;
			}
			speed = newSpeed;						
			
			cornerTiles = CoordinateUtil.getCorners(this, map, engine, x, y + speed * yFactor); 
			
			if(yFactor == -1){
				if(cornerTiles.upleft && cornerTiles.upright){
					y += speed * yFactor;
				}else{
					y = currentCoordinates.yTile * map.tileH + (height * 0.5);
					jumpSpeed = 0;
				}
			}
			
			if(yFactor == 1){
				if(cornerTiles.downleft && cornerTiles.downright && !checkIfOnCloud()){
					y += speed * yFactor;
				}else{
					y = (currentCoordinates.yTile + 1) * map.tileH - (height * 0.5);
					isJumping = false;
				}
			}
			
			cornerTiles = CoordinateUtil.getCorners(this, map, engine, x + speed * xFactor, y);
			
			if(xFactor == -1){
				if(cornerTiles.downleft && cornerTiles.upleft){
					x += speed * xFactor;
					fall();
				}else{
					x = currentCoordinates.xTile * map.tileW + (width * 0.5);
				}
			}
			
			if(xFactor == 1){
				if(cornerTiles.upright && cornerTiles.downright){
					x += speed * xFactor;
					fall();
				}else{
					x = (currentCoordinates.xTile + 1) * map.tileW - (width * 0.5);
				}
			}
			
			update();
		}
		
		public function fall():void
		{
			if(!isJumping){
				cornerTiles = CoordinateUtil.getCorners(this, map, engine, x, y + 1);
				if(cornerTiles.downleft && cornerTiles.downright && !checkIfOnCloud()){
					jumpSpeed = 0;
					isJumping = true;
				}
			}
			
			isClimbing = false;
		}
		
		public function jump():void
		{
			jumpSpeed = jumpSpeed + gravity;
			
			if(jumpSpeed > map.tileH - (height * 0.5)){
				jumpSpeed = map.tileH - (height * 0.5);
			}
			
			if(jumpSpeed < 0){
				move(0, -1, -1)
			}else if(jumpSpeed > 0){
				move(0, 1, 1)
			}
		}
		
		public function climb(yFactor:Number):void
		{
			isClimbing = true;
			isJumping = false;
			y += speed * yFactor;
			x = (currentCoordinates.xTile * map.tileW) + (map.tileW * 0.5);
		}
		
		public function update():void
		{
			currentCoordinates.xTile = Math.floor(x / map.tileW);
			currentCoordinates.yTile = Math.floor(y / map.tileH);
		}
		
		private function checkIfOnCloud():Boolean
		{
			var bol:Boolean;
			
			var leftcloud:Boolean = BaseTile(engine.getChildByName("tile_" + cornerTiles.downY + "_" + cornerTiles.leftX)).isCloud;
			var rightcloud:Boolean = BaseTile(engine.getChildByName("tile_" + cornerTiles.downY + "_" + cornerTiles.rightX)).isCloud;
			
			if(leftcloud || rightcloud){
				bol = true;
			}else{
				bol = false;
			}			
			
			return bol;
		}
		
		public function checkForUpLadder():Boolean
		{
			var bol:Boolean;
			var downY:Number = Math.floor((y + (height * 0.5) - 1) / map.tileH);
			var upY:Number = Math.floor(((y - (height * 0.5)) - speed) / map.tileW);
			var upLadder:Boolean = BaseTile(engine.getChildByName("tile_" + upY + "_" + currentCoordinates.xTile)).isLadder;
			var downLadder:Boolean = BaseTile(engine.getChildByName("tile_" + downY + "_" + currentCoordinates.xTile)).isLadder;
			var upBlock:Boolean = BaseTile(engine.getChildByName("tile_" + upY + "_" + currentCoordinates.xTile)).walkable;
			
			if(upLadder || upBlock){
				if(upLadder || downLadder){
					bol = true;
				}
			}else{
				y = currentCoordinates.yTile * map.tileH + (height * 0.5);
    			update();
    			bol = false
			}
			
			return bol;
		}
		
		public function checkForDownLadder():Boolean
		{
			var bol:Boolean;
			var downY:Number = Math.floor((speed + y + (height * 0.5)) / map.tileH);
			var downLadder:Boolean = BaseTile(engine.getChildByName("tile_" + downY + "_" + currentCoordinates.xTile)).isLadder;
			
			if(downLadder){
				bol = true;
			}else{
				fall();
				bol = false
			}
			
			return bol;
		}
		
		/*
		properties
		*/
		
		public function get charWidth():Number
		{
			return _charWidth;
		}

		public function set charWidth(value:Number):void
		{
			_charWidth = value;
		}

		public function get charHeight():Number
		{
			return _charHeight;
		}

		public function set charHeight(value:Number):void
		{
			_charHeight = value;
		}

		public function get defColor():Number
		{
			return _defColor;
		}

		public function set defColor(value:Number):void
		{
			_defColor = value;
		}

		public function get currentCoordinates():Coordinates
		{
			return _currentCoordinates;
		}

		public function set currentCoordinates(value:Coordinates):void
		{
			_currentCoordinates = value;
		}

		public function get cornerTiles():CornersData
		{
			return _cornerTiles;
		}

		public function set cornerTiles(value:CornersData):void
		{
			_cornerTiles = value;
		}

		public function get jumpSpeed():Number
		{
			return _jumpSpeed;
		}

		public function set jumpSpeed(value:Number):void
		{
			_jumpSpeed = value;
		}

		public function get jumpStart():Number
		{
			return _jumpStart;
		}

		public function set jumpStart(value:Number):void
		{
			_jumpStart = value;
		}

		public function get gravity():Number
		{
			return _gravity;
		}

		public function set gravity(value:Number):void
		{
			_gravity = value;
		}

		public function get controllable():Boolean
		{
			return _controllable;
		}

		public function set controllable(value:Boolean):void
		{
			_controllable = value;
		}

		public function get isJumping():Boolean
		{
			return _isJumping;
		}

		public function set isJumping(value:Boolean):void
		{
			_isJumping = value;
		}

		public function get isClimbing():Boolean
		{
			return _isClimbing;
		}

		public function set isClimbing(value:Boolean):void
		{
			_isClimbing = value;
		}
		
		public function get engine():GameEngine
		{
			return _engine;
		}

		public function set engine(value:GameEngine):void
		{
			_engine = value;
		}

		public function get map():IMap
		{
			return _map;
		}

		public function set map(value:IMap):void
		{
			_map = value;
		}

		public function get speed():Number
		{
			return _speed;
		}

		public function set speed(value:Number):void
		{
			_speed = value;
			if(!originalSpeedSet){
				originalSpeedSet = true;
				originalSpeed = _speed;
			}
		}
	}
}